import tkinter as tk
from tkinter import ttk, messagebox
import json
import os

class Student:
    def __init__(self, name, scores=None):
        self.name = name
        self.scores = scores if scores is not None else {}

    def total_score(self):
        return sum(self.scores.values())
#用来后续数据存储使用的 to_dict函数
    def to_dict(self):
        return {
            "name": self.name,
            "scores": self.scores,
        }

    @classmethod
#from_dict函数用来后续下载数据
    def from_dict(cls, data):
        return cls(
            name=data["name"],
            scores=data.get("scores", {}),
        )

    def __repr__(self):
        return f"name: {self.name}, grades: {self.scores}, sum: {self.total_score()}"


#使用bubble排序通过名字或者学生成绩进行排序
def bubble_sort(students, by="name"):
    n = len(students)
    for i in range(n):
        for j in range(0, n-i-1):
            if by == "name":
                if students[j].name > students[j+1].name:
                    students[j], students[j+1] = students[j+1], students[j]
            elif by == "total_score":
                if students[j].total_score() < students[j+1].total_score():
                    students[j], students[j+1] = students[j+1], students[j]
    return students

class StudentManager:
    def __init__(self, root):
        self.root = root
        self.root.title("student management system")
    #字典就是哈希表，这里students作为哈希表
        self.students = []
        
        self.courses = ["Math", "English", "Physics"]
        self.scores = {}

        # 设置窗口大小
        self.root.geometry('600x500')

        # 输入学生信息的框架
        frame_input = tk.LabelFrame(root, text="add imformation", padx=10, pady=10)
        frame_input.pack(padx=10, pady=10, fill='x', expand=True)

        tk.Label(frame_input, text="name").grid(row=0, column=0, padx=5, pady=5, sticky='e')
        self.name_entry = tk.Entry(frame_input)
        self.name_entry.grid(row=0, column=1, padx=5, pady=5, sticky='ew')

        tk.Label(frame_input, text="class").grid(row=1, column=0, padx=5, pady=5, sticky='e')
        self.course_combobox = ttk.Combobox(frame_input, values=self.courses)
        self.course_combobox.grid(row=1, column=1, padx=5, pady=5, sticky='ew')

        tk.Label(frame_input, text="grades").grid(row=1, column=2, padx=5, pady=5, sticky='e')
        self.score_entry = tk.Entry(frame_input)
        self.score_entry.grid(row=1, column=3, padx=5, pady=5, sticky='ew')
        tk.Button(frame_input, text="add grades", command=self.add_score).grid(row=1, column=4, padx=5, pady=5)

        # 显示已添加的成绩清单
        self.score_listbox = tk.Listbox(frame_input, width=40)
        self.score_listbox.grid(row=2, column=0, columnspan=5, padx=5, pady=5, sticky='ew')

        # 计算总成绩按钮
        tk.Button(frame_input, text="sum and add ", command=self.calculate_total_and_add_student).grid(row=3, column=0, columnspan=5, padx=5, pady=5)

        # 按钮
        frame_buttons = tk.Frame(root)
        frame_buttons.pack(fill='x', padx=10, pady=10)
        
        tk.Button(frame_buttons, text="name sort", command=lambda: self.update_student_list('name')).pack(side=tk.LEFT, padx=5)
        tk.Button(frame_buttons, text="grade sort ", command=lambda: self.update_student_list('total_score')).pack(side=tk.LEFT, padx=5)

        # 学生列表框
        frame_listbox = tk.LabelFrame(root, text="list", padx=10, pady=10)
        frame_listbox.pack(fill='both', expand=True, padx=10, pady=10)
        
        # 增加 Listbox 高度以显示更多学生
        self.listbox = tk.Listbox(frame_listbox, width=80)  # 修改这里以显示更多条目
        self.listbox.pack(side=tk.LEFT, fill='both', expand=True)

        scrollbar = tk.Scrollbar(frame_listbox, orient="vertical", command=self.listbox.yview)
        scrollbar.pack(side=tk.RIGHT, fill='y')
        self.listbox['yscrollcommand'] = scrollbar.set

        self.load_students_info()

    def add_score(self):
        course = self.course_combobox.get()
        score = self.score_entry.get()
        if course and score.isdigit():
            self.scores[course] = int(score)
            self.score_listbox.insert(tk.END, f"{course}: {score}")
            messagebox.showinfo("success", f"grades {score} have added to sum {course}")
        else:
            messagebox.showerror("wrong", "please enter useful data ")

    def calculate_total_and_add_student(self):
        total = sum(self.scores.values())
        messagebox.showinfo("sum", f"sum: {total}")

        name = self.name_entry.get()
        if any(student.name == name for student in self.students):
            messagebox.showerror("wrong", "please enter another name ")
            return
        
        for course in self.courses:
            if course not in self.scores:
                self.scores[course] = 0

        if self.scores:
            student = Student(name=name, scores=self.scores.copy())
            self.students.append(student)
            self.save_student_info()
            messagebox.showinfo("sucess", f"student {name} imformation added ")
            self.update_student_list()
            self.scores.clear()
            self.score_listbox.delete(0, tk.END)  # 清空成绩清单
        else:
            messagebox.showerror("wrong", "at least one ")

    def save_student_info(self):
        with open('students.json', 'w', encoding='utf-8') as file:
            json.dump([student.to_dict() for student in self.students], file, ensure_ascii=False, indent=4)

    def load_students_info(self):
        if os.path.exists('students.json'):
            with open('students.json', 'r', encoding='utf-8') as file:
                data = json.load(file)
                self.students = [Student.from_dict(s) for s in data]
        self.update_student_list()

    def update_student_list(self, sort_by="name"):
        self.listbox.delete(0, tk.END)
        for student in bubble_sort(self.students, by=sort_by):
            self.listbox.insert(tk.END, str(student))

if __name__ == "__main__":
    root = tk.Tk()
    app = StudentManager(root)
    root.mainloop()